/*
 * utils.h
 *
 *  Created on: Sep 26, 2013
 * @author Daniel Rogers
 *
 */

#ifndef UTILS_H_
#define UTILS_H_

#include <stdint.h>
#include <stdio.h>
#include <math.h>

#define FACT12 (12 * FACT11)
#define FACT11 (11 * FACT10)
#define FACT10 (10 * FACT9)
#define FACT9 (9 * FACT8)
#define FACT8 (8 * FACT7)
#define FACT7 (7 * FACT6)
#define FACT6 (6 * FACT5)
#define FACT5 (5 * FACT4)
#define FACT4 (4 * FACT3)
#define FACT3 (3 * FACT2)
#define FACT2 2

//Corners have 8! * 3^7 states, values occupy 4 bits
#define CORNER_SLOTS ((FACT8 * 2187) / 2)
//Edges have 12! / 6! * 2^6 states, values occupy 4 bits
#define EDGE_SLOTS (((FACT12 / FACT6) * (1 << 6)) / 2)

/*
 * Base 3 encode a 16 bit string with n values
 *
 * @param str The string of base3 values to encode. Each value must occupy 2
 *              bits in the src string
 * @param n The number of values it contains
 * @return The compressed string
 */
static inline uint16_t base3Encode(uint16_t str, uint8_t n)
{
    uint16_t ret = 0;
    //Next power of 3 to mul by
    uint16_t p3 = 1;

    for(uint8_t i = 0; i < n; ++i)
    {
        //Isolate last 2 bits, multiply by power of 3
        // and put in ret
        ret += (p3 * (str & 0x3));
        //Increment power of 3
        p3 *= 3;
        //Remove old bits
        str >>= 2;
    }

    return (ret);
}

/*
 * Decode a base 3 16 bit string into n values
 *
 * @param str The string of base3 values to decode.
 * @param n The number of values it contains
 * @return The decompressed string, each value will occupy 2 bits
 */
static inline uint16_t base3Decode(uint16_t str, uint8_t n)
{
    uint16_t ret = 0;
    //Next power of 3 to div by
    uint16_t p3 = pow(3, n-1);

    for(uint8_t i = 0; i < n; ++i)
    {
        //Allocate space in ret for next
        ret <<= 2;
        //Get highest power of 3 in str and put it in ret
        ret += (str / p3);
        //Remove old value
        str %= p3;
        //Decrement power of 3
        p3 /= 3;
    }

    return (ret);
}

/*
 * Circular 32bit shift left by 8 places
 *
 * @param val The 32bit value to shift, this will be modified in place
 */
static inline void circShift_int32L8(uint32_t * val)
{

    //Circular shift
    uint32_t hi_part = (*val) << 8;
    //0xF000 0000 -> 0x0000 000F
    uint32_t lo_part = (*val) >> 24;

    //set val to circular shift
    *val = (hi_part | lo_part);
}

/*
 * Circular 32bit shift right by 8 places
 *
 * @param val The 32bit value to shift, this will be modified in place
 */
static inline void circShift_int32R8(uint32_t * val)
{

    //Circular shift
    uint32_t lo_part = (*val) >> 8;
    //0x0000 000F -> 0xF000 0000
    uint32_t hi_part = (*val) << 24;

    //set val to circular shift
    *val = (hi_part | lo_part);
}

#endif /* UTILS_H_ */
